Affiliates & Resellers

Status: Spec complete. Nothing built yet except tracking columns in D1 and worker ref writes. Portal, redirect worker, blast system — all pending. Last updated: May 2026 Read this before any affiliate or reseller session. Do not infer. Do not guess.


The Two Models — Definitions

Reseller (Training Provider / TP)

Affiliate


All Decisions Made

Decision Chosen Reason
Portal location affiliates.claritysystems.work Not course-specific. One portal, all courses, forever.
ref code format Random 6-char slug e.g. x7k2mp Privacy between affiliates. Not name-based.
Commission rate model KV default floor, D1 override per affiliate No self-selection or categories. Lovinia controls all rates.
Tracking link format Permanent redirect via /r/[ref] Captures impressions (clicks) + conversions. Link never changes.
Redirect destination One KV entry affiliate:redirect controls all links Update one entry = all links point to new course instantly
Blast trigger /blast command to Telegram bot Lovinia sends one message, bot handles the rest. Private, no channel.
Blast content — Telegram Image from R2 + personal link in message body Lovinia uploads new image to R2 per course, updates one KV entry
Blast content — Email Plain email + PDF attached from R2 + HTML template from KV Template never redesigned. Only vars change per course.
Email template storage KV (text, injected with vars at send time) Faster than R2 fetch. Worker injects vars before sending via Resend.
PDF storage R2 Binary file. One upload per course. URL stored in KV.
Affiliate dashboard Not built Build when 3+ active affiliates ask for it.
Telegram notifications Bot messages Lovinia on every conversion. Messages affiliate only if Chat ID provided. Not all affiliates are Telegram users.
Affiliate Telegram Chat ID Optional at signup Affiliates who post on social or WhatsApp and aren't Telegram-savvy still tracked and notified by email.
Conversion notification to affiliate Telegram if Chat ID provided + email always Worker: if telegram_chat_id exists → send Telegram. Send email regardless.
Affiliate privacy One-to-one bot messages only. No group. No channel. Affiliates never see each other.
Link delivery on signup Email only. Not shown on page. Email is permanent record. Eliminates "I lost my link" support.
Reseller affiliate sub-model Out of scope TP's internal arrangement. Absorbed before paying Lovinia.

What Is Live (as of May 2026)

What Is NOT Built Yet


Pending Fix — Register Page Card/FPX Paths

Problem: Card and FPX payment paths do not pass tier or is_earlybird to the worker. Commission calculation will be wrong without these.

Fix: Pass tier (single/duo/fivepax) and is_earlybird (true/false based on earlybird deadline) in POST body from register/index.njk on both card and FPX paths. Worker writes to D1.

Do this before portal launches. Conversion Telegram messages show commission amount — that number will be wrong without tier and price point.


Full System Architecture

The sequence — signup to conversion to blast

SIGNUP
  Affiliate visits affiliates.claritysystems.work
  Reads page: what it is, how it works, what they earn, FAQ
  Opens Telegram → messages bot → receives their Chat ID
  Fills form: name, email, company, Chat ID
  Submits
  Worker: generates ref code → writes affiliates table → sends confirmation email → Telegrams Lovinia
  Page: "Check your inbox."
  Email arrives: their permanent link + full terms + current course details

SHARING
  Affiliate shares affiliates.claritysystems.work/r/x7k2mp anywhere
  Someone clicks it
  Worker: logs click to `clicks` table → fetches affiliate:redirect from KV → redirects to [destination]?ref=x7k2mp
  Visitor lands on pricing page with ref in URL
  Ref passes through all links (pricing → register / enquiry / hrdc grant)

CONVERSION
  Visitor submits any form or hits Stripe redirect
  Worker: writes enquiry row with ref, tier, is_earlybird, form_type, hrdc_option
  Worker: looks up affiliate by ref → gets commission_pct (D1 override or KV default)
  Worker: looks up tier price from KV course data → calculates commission
  Worker: Telegrams Lovinia (full details + commission amount)
  Worker: Telegrams affiliate (what they chose + estimated commission + payment timeline)

NEW COURSE BLAST
  Lovinia: uploads new Telegram image to R2 → updates affiliate:blast_image_url in KV
  Lovinia: uploads new PDF to R2 → updates affiliate:blast_pdf_url in KV
  Lovinia: updates KV blast vars (course name, dates, city, venue, earlybird price, deadline)
  Lovinia: updates affiliate:redirect in KV to new course pricing page URL
  Lovinia: sends /blast to Telegram bot
  Bot: confirms it's Lovinia's Chat ID → fetches all active affiliates from D1
  Bot: for each affiliate:
    → sends Telegram image + message with their personal link
    → sends email: HTML template (fetched from KV, vars injected) + PDF attached from R2
  Every affiliate link already points to new course. No link update needed on their end.

KV Entries — Full List

All keys prefixed affiliate:. Set once, update per course where noted.

Key Value When to update
affiliate:redirect Current course pricing page URL Every new course
affiliate:default_commission_pct e.g. 10 When default rate changes
affiliate:blast_image_url R2 public URL of Telegram course image Every new course
affiliate:blast_pdf_url R2 public URL of course PDF brochure Every new course
affiliate:blast_course_name e.g. Sales For Technical People Every new course
affiliate:blast_dates e.g. June 17–18, 2026 Every new course
affiliate:blast_city e.g. George Town, Penang Every new course
affiliate:blast_venue e.g. E&O Hotel Every new course
affiliate:blast_earlybird_price e.g. RM 2,800 Every new course
affiliate:blast_earlybird_deadline e.g. 17 May 2026 Every new course
email:affiliate_blast_template Full HTML email template string with `` When design changes
email:affiliate_signup_template Full HTML email template string for signup confirmation When design changes

Email template placeholders

Both templates share the same placeholder format: ``

Blast email vars: ``

Signup confirmation vars: ``


D1 Schema — Full Target State

affiliates table

CREATE TABLE affiliates (
  id               TEXT PRIMARY KEY,   -- random ref code e.g. 'x7k2mp'
  name             TEXT NOT NULL,
  email            TEXT NOT NULL,
  company          TEXT,
  telegram_chat_id TEXT,               -- optional. if null, notifications go to email only.
  commission_pct   REAL,               -- null = use KV default
  status           TEXT NOT NULL DEFAULT 'active',
  created_at       TEXT NOT NULL DEFAULT (datetime('now'))
);

Columns to add to existing affiliates table

ALTER TABLE affiliates ADD COLUMN company          TEXT;
ALTER TABLE affiliates ADD COLUMN telegram_chat_id TEXT;
ALTER TABLE affiliates ADD COLUMN commission_pct   REAL;

Columns to add to existing enquiries table

ALTER TABLE enquiries ADD COLUMN tier         TEXT;
ALTER TABLE enquiries ADD COLUMN is_earlybird INTEGER DEFAULT 0;

clicks table — create new

CREATE TABLE clicks (
  id         TEXT PRIMARY KEY,
  ref        TEXT NOT NULL,
  clicked_at TEXT NOT NULL DEFAULT (datetime('now')),
  ip_hash    TEXT,
  user_agent TEXT
);

Workers — Functions Required

Worker: affiliates-worker (new, on affiliates.claritysystems.work)

Routes:

GET /r/:ref — Click-tracking redirect

  1. Look up ref in D1 affiliates table. If not found → redirect to affiliate:redirect without ref.
  2. Write row to clicks table: id (UUID), ref, clicked_at, ip_hash (SHA-256 of IP), user_agent
  3. Fetch affiliate:redirect from KV
  4. 302 redirect to [destination]?ref=[ref]

POST /signup — Affiliate registration

  1. Read body: name, email, company, telegram_chat_id (optional)
  2. Validate: name, email required. Email format valid. If telegram_chat_id provided, must be numeric.
  3. Check duplicate: if email already in affiliates table → return error "Already registered"
  4. Generate ref: 6-char random alphanumeric, check not already in use in D1
  5. Write to affiliates table
  6. Fetch email:affiliate_signup_template from KV
  7. Inject vars: affiliate_name, affiliate_link, course_name, dates, commission_pct (KV default)
  8. Send via Resend: plain email subject + HTML body. No PDF on signup email.
  9. Telegram to Lovinia: new signup notification (name, email, company, ref, link)
  10. Return { ok: true }

POST /blast (Telegram bot webhook, Lovinia only)

  1. Verify message is from Lovinia's Chat ID. Reject all others silently.
  2. Parse command: /blast → trigger blast. Any other command → ignore.
  3. Fetch all active affiliates from D1 (WHERE status = 'active')
  4. Fetch all blast KV vars in parallel
  5. Fetch HTML template from KV (email:affiliate_blast_template)
  6. For each affiliate: a. Inject vars into HTML template including affiliate_name and affiliate_link b. Send Telegram: image (from affiliate:blast_image_url) + text message with their link c. Send email via Resend: subject, HTML body, PDF attached (fetched from affiliate:blast_pdf_url)
  7. Telegram to Lovinia on completion: "Blast sent to [n] affiliates."

Worker: trainingbiz-admin-clerk (existing — additions only)

On any enquiry write where ref is not null:

  1. Look up affiliate in D1 by ref
  2. Resolve commission rate: affiliate.commission_pct ?? KV affiliate:default_commission_pct
  3. Look up tier price from KV course data using tier + is_earlybird
  4. Calculate commission: price × rate / 100
  5. Send Telegram to Lovinia (existing notification — add commission fields)
  6. Send Telegram to affiliate's telegram_chat_id if present (not null). Always send conversion email to affiliate regardless.

Commission Rate Logic

Set default:

wrangler kv key put --namespace-id=<CAC_KV_ID> "affiliate:default_commission_pct" "10"

Override per affiliate:

UPDATE affiliates SET commission_pct = 15 WHERE id = 'x7k2mp';

Telegram Notification Formats

To Lovinia — new affiliate signup

🔗 New affiliate signed up
Name: [name]
Email: [email]
Company: [company or —]
Ref: [ref]
Link: affiliates.claritysystems.work/r/[ref]

To Lovinia — conversion

💰 Affiliate conversion
Affiliate: [name] ([ref])
Lead: [contact_person] — [email]
Path: [form_type] / [hrdc_option]
Tier: [tier] — [Early Bird / Standard]
Est. value: RM [amount]
Est. commission: [rate]% → RM [calculated]

To affiliate — conversion

✅ Your link just converted
Someone registered via your link.
What they chose: [tier] — [Early Bird / Standard]
Estimated commission: RM [calculated]
We confirm and pay within [X days] after the event.

To affiliate — blast (new course)

[Image: course Telegram graphic from R2]

🗓 [Course name] is open
[Dates] · [City] · [Venue]
Early bird: [price] — closes [deadline]

Your link (unchanged):
affiliates.claritysystems.work/r/[their ref]

Share it now. It already points to the new course.

To Lovinia — blast complete

✅ Blast sent to [n] affiliates.

Content and Design — Pending (Do Before Build)

These must be completed before any build session starts. The build session will implement, not decide.

1. Landing page — affiliates.claritysystems.work

Sections to write:

Design reference: Match claritysystems.work aesthetic — JetBrains Mono, Cormorant Garamond, cold red, near black, clean.

2. FAQ — questions to answer

Answers: Lovinia to provide before build session. Agent drafts, Lovinia approves.

3. Email template — signup confirmation

Plain structure, HTML rendered:

4. Email template — blast (new course announcement)

Plain structure, HTML rendered:

5. Telegram course image

6. Course PDF brochure


Tracking Queries

All leads from one affiliate:

SELECT contact_person, email, company_name, form_type, hrdc_option, tier, is_earlybird, status, submitted_at
FROM enquiries WHERE ref = 'x7k2mp'
ORDER BY submitted_at DESC;

All affiliates — clicks, leads, conversions:

SELECT
  a.id, a.name, a.email, a.commission_pct,
  COUNT(DISTINCT c.id) as clicks,
  COUNT(DISTINCT e.id) as leads,
  SUM(CASE WHEN e.status = 'stripe_redirect' THEN 1 ELSE 0 END) as went_to_stripe,
  SUM(CASE WHEN e.status = 'confirmed' THEN 1 ELSE 0 END) as confirmed,
  SUM(CASE WHEN e.status = 'paid' THEN 1 ELSE 0 END) as paid
FROM affiliates a
LEFT JOIN clicks c ON c.ref = a.id
LEFT JOIN enquiries e ON e.ref = a.id
GROUP BY a.id ORDER BY clicks DESC;

Stripe redirects to cross-reference with Stripe:

SELECT ref, contact_person, email, tier, is_earlybird, submitted_at
FROM enquiries
WHERE ref IS NOT NULL AND status = 'stripe_redirect'
ORDER BY submitted_at DESC;

Mark confirmed and paid:

UPDATE enquiries SET status = 'confirmed' WHERE email = '[email protected]' AND ref = 'x7k2mp';
UPDATE enquiries SET status = 'paid'      WHERE email = '[email protected]' AND ref = 'x7k2mp';

Quick Start — Give Out Links Today (No Portal Needed)

Skip the portal, the redirect worker, and the blast system entirely. The conversion tracking already works. Do this to get 5 links live immediately.

Step 1 — D1 migrations (Console, run once):

ALTER TABLE affiliates ADD COLUMN company          TEXT;
ALTER TABLE affiliates ADD COLUMN telegram_chat_id TEXT;
ALTER TABLE affiliates ADD COLUMN commission_pct   REAL;

Step 2 — Insert affiliates manually:

INSERT INTO affiliates (id, name, email, company, status) VALUES
  ('a1b2c3', 'Name One',   '[email protected]', 'Company A', 'active'),
  ('d4e5f6', 'Name Two',   '[email protected]', 'Company B', 'active'),
  ('g7h8i9', 'Name Three', '[email protected]', '',          'active'),
  ('j1k2l3', 'Name Four',  '[email protected]', '',          'active'),
  ('m4n5o6', 'Name Five',  '[email protected]', '',          'active');

Replace names, emails, ref codes with your actual data. Ref codes are 6 chars, any alphanumeric.

Step 3 — Their link (send directly, no portal):

https://claritysystems.work/sales-training/pricing/?ref=a1b2c3

Send each person their link via WhatsApp, email, whatever. Tell them to share it as-is.

Step 4 — Verify a conversion:

SELECT ref, contact_person, email, form_type, status, submitted_at
FROM enquiries WHERE ref IS NOT NULL ORDER BY submitted_at DESC;

What you lose vs full system: impression/click counting. What you keep: full conversion tracking, ref in every D1 enquiry row. Good enough to validate the system and pay affiliates.


Build Order — Full System (Next Build Session)

Prerequisites before this session starts:

Build steps — in order. Do not skip.

  1. D1 migrations (run in D1 Console):
ALTER TABLE affiliates ADD COLUMN company          TEXT;
ALTER TABLE affiliates ADD COLUMN telegram_chat_id TEXT;
ALTER TABLE affiliates ADD COLUMN commission_pct   REAL;
ALTER TABLE enquiries  ADD COLUMN tier             TEXT;
ALTER TABLE enquiries  ADD COLUMN is_earlybird     INTEGER DEFAULT 0;
CREATE TABLE clicks (
  id TEXT PRIMARY KEY,
  ref TEXT NOT NULL,
  clicked_at TEXT NOT NULL DEFAULT (datetime('now')),
  ip_hash TEXT,
  user_agent TEXT
);
  1. Set KV entries (run once):
wrangler kv key put --namespace-id=<CAC_KV_ID> "affiliate:default_commission_pct" "[rate]"
wrangler kv key put --namespace-id=<CAC_KV_ID> "affiliate:redirect" "https://claritysystems.work/sales-training/pricing/"
wrangler kv key put --namespace-id=<CAC_KV_ID> "affiliate:blast_image_url"          "[R2 URL]"
wrangler kv key put --namespace-id=<CAC_KV_ID> "affiliate:blast_pdf_url"            "[R2 URL]"
wrangler kv key put --namespace-id=<CAC_KV_ID> "affiliate:blast_course_name"        "[name]"
wrangler kv key put --namespace-id=<CAC_KV_ID> "affiliate:blast_dates"              "[dates]"
wrangler kv key put --namespace-id=<CAC_KV_ID> "affiliate:blast_city"               "[city]"
wrangler kv key put --namespace-id=<CAC_KV_ID> "affiliate:blast_venue"              "[venue]"
wrangler kv key put --namespace-id=<CAC_KV_ID> "affiliate:blast_earlybird_price"    "[price]"
wrangler kv key put --namespace-id=<CAC_KV_ID> "affiliate:blast_earlybird_deadline" "[date]"
# Upload HTML templates last — after copy is approved
wrangler kv key put --namespace-id=<CAC_KV_ID> "email:affiliate_signup_template"    "$(cat signup-email.html)"
wrangler kv key put --namespace-id=<CAC_KV_ID> "email:affiliate_blast_template"     "$(cat blast-email.html)"
  1. Fix register page — pass tier and is_earlybird in POST body on card/FPX paths (register/index.njk)

  2. Update trainingbiz-admin-clerk — add affiliate Telegram notification on conversion (look up telegram_chat_id by ref, send message)

  3. Build affiliates-worker — new worker on affiliates.claritysystems.work:

  4. Build affiliate portal static page — affiliates.claritysystems.work on Cloudflare Pages

  5. Wire Telegram bot webhook to /blast endpoint

  6. Live test:


When a New Course Opens — Lovinia's Checklist

[ ] Design Telegram image → upload to R2 → copy public URL
[ ] Design PDF brochure → upload to R2 → copy public URL
[ ] Update KV: affiliate:blast_image_url
[ ] Update KV: affiliate:blast_pdf_url
[ ] Update KV: affiliate:blast_course_name
[ ] Update KV: affiliate:blast_dates
[ ] Update KV: affiliate:blast_city
[ ] Update KV: affiliate:blast_venue
[ ] Update KV: affiliate:blast_earlybird_price
[ ] Update KV: affiliate:blast_earlybird_deadline
[ ] Update KV: affiliate:redirect  ← new course pricing page URL
[ ] Send /blast to bot
[ ] Done. All affiliate links now point to new course. All affiliates notified.

Dependencies

Depends on Why
claritysystems-db D1 All affiliate, enquiry, click data
CAC_KV Commission rates, redirect destination, blast vars, email templates
R2 Telegram image and PDF per course
trainingbiz-admin-clerk worker Enquiry writes, conversion Telegram to affiliate
affiliates-worker (new) Redirect, signup, blast
Resend All affiliate emails
Telegram bot All notifications — Lovinia and affiliates
Cloudflare Pages Hosts affiliate portal static page

Chatgpt update :

## Affiliate Tracking Build Fixes — May 2026

Today we fixed the affiliate tracking system end-to-end.

The core issue was not one single bug. It was a chain of deployment, routing, layout, DNS, and Worker configuration problems.

---

## 1. Fixed the wrong Worker being recreated

Problem:

GitHub/Wrangler kept recreating the wrong Worker because the repo config still said:

```toml
name = "affiliates-worker"

But the actual intended Worker in Cloudflare was:

affilliates-worker

Fix:

Updated:

workers/affiliates-worker/wrangler.toml

to:

name = "affilliates-worker"
main = "src/index.js"
compatibility_date = "2024-09-23"
workers_dev = false

Result:

Deploys now go to the correct Cloudflare Worker instead of recreating the deleted/wrong Worker.


2. Fixed Worker admin login 1101 error

Problem:

The Worker threw Cloudflare Error 1101 because it used relative redirects like:

Response.redirect("/admin/login", 302)
Response.redirect("/admin", 302)

Cloudflare Worker runtime complained:

Unable to parse URL: /admin/login

Fix:

Changed relative redirects to absolute redirects:

Response.redirect(new URL("/admin/login", request.url).toString(), 302)
Response.redirect(new URL("/admin", request.url).toString(), 302)

Also changed response headers like:

Location: "/admin"

to:

Location: new URL("/admin", request.url).toString()

File changed:

workers/affiliates-worker/src/index.js

Result:

Admin login now works.


3. Confirmed D1 tables and columns

Confirmed the required D1 tables exist:

affiliates
clicks

Confirmed affiliates has the needed working columns:

id
name
phone
email
company
status
created_at

Result:

The admin panel can create affiliate records, and the Worker can look up active affiliate refs.


4. Confirmed Worker redirect works

Correct test command:

curl -s -D - -o /dev/null https://affiliates.claritysystems.work/r/ckl244

Important: do not use curl -I.

Reason:

curl -I

sends a HEAD request.

The Worker route only handles:

if (request.method === "GET" && url.pathname.startsWith("/r/"))

So curl -I returns 404 even when the browser/GET route works.

Correct result:

HTTP/2 302
location: https://claritysystems.work/sales-training/?ref=ckl244

Result:

The affiliate redirect route works.


5. Added cross-site affiliate ref persistence

Problem:

Affiliate links correctly landed with:

?ref=ckl244

But when visitors clicked other pages, the ref disappeared.

Initial wrong assumption:

Adding the script only to:

_includes/base.njk

was not enough.

Reason:

The site uses mixed architecture:

Articles use _includes/base.njk
Pricing page is standalone: sales-training/pricing/index.njk
Sales pages are standalone .njk files
Home page is plain index.html

So the script had to be added to all standalone pages too.

Files patched included:

_includes/base.njk
sales-training/pricing/index.njk
sales-training/pricing-hrdc-grant-claim/index.njk
sales-training/register/index.njk
sales-training/enquiry/index.njk
sales-training/request-hrdc-grant-claim/index.njk
sales-training/index.njk
sales-training/about/index.njk
sales-training/about/Lovinia.njk
sales-training/articles/index.njk
resellers/newrise/articles/index.njk
index.html

Script purpose:

1. Read ?ref= and ?ch= from landing URL
2. Save them into localStorage and cookie
3. Append ref/ch to internal same-origin links
4. Skip external links, mailto, tel, anchors, and javascript links

Core script added:

<script>
// Affiliate ref persistence — runs on every page
(function () {
  const params = new URLSearchParams(window.location.search);
  const refFromUrl = params.get('ref');
  const chFromUrl  = params.get('ch');

  if (refFromUrl) {
    localStorage.setItem('aff_ref', refFromUrl);
    document.cookie = 'aff_ref=' + encodeURIComponent(refFromUrl) + '; Path=/; Max-Age=' + (60 * 60 * 24 * 30) + '; SameSite=Lax';
  }

  if (chFromUrl) {
    localStorage.setItem('aff_ch', chFromUrl);
    document.cookie = 'aff_ch=' + encodeURIComponent(chFromUrl) + '; Path=/; Max-Age=' + (60 * 60 * 24 * 30) + '; SameSite=Lax';
  }

  const ref = refFromUrl || localStorage.getItem('aff_ref') || '';
  const ch  = chFromUrl  || localStorage.getItem('aff_ch')  || '';

  if (!ref) return;

  document.querySelectorAll('a[href]').forEach(function (a) {
    try {
      const href = a.getAttribute('href');
      if (!href) return;
      if (href.startsWith('#')) return;
      if (href.startsWith('mailto:')) return;
      if (href.startsWith('tel:')) return;
      if (href.startsWith('javascript:')) return;

      const linkUrl = new URL(href, window.location.origin);
      if (linkUrl.origin !== window.location.origin) return;

      linkUrl.searchParams.set('ref', ref);
      if (ch) linkUrl.searchParams.set('ch', ch);

      a.href = linkUrl.toString();
    } catch (e) {}
  });
})();
</script>

Verification commands:

curl -s "https://claritysystems.work/?ref=ckl244&v=$(date +%s)" | grep "Affiliate ref persistence" || echo "HOME MISSING"

curl -s "https://claritysystems.work/sales-training/?ref=ckl244&v=$(date +%s)" | grep "Affiliate ref persistence" || echo "SALES TRAINING MISSING"

curl -s "https://claritysystems.work/sales-training/pricing/?ref=ckl244&v=$(date +%s)" | grep "Affiliate ref persistence" || echo "PRICING MISSING"

Final result:

All main pages now include the persistence script.


6. Added cleaner public tracking subdomain

Original generated affiliate links looked like:

https://affiliates.claritysystems.work/r/ckl244

Concern:

The word affiliates made the referral nature too obvious in the shared URL.

New structure:

Admin / portal:
https://affiliates.claritysystems.work/admin

Public tracking link:
https://go.claritysystems.work/r/ckl244

Destination:
https://claritysystems.work/sales-training/?ref=ckl244

Cloudflare DNS added:

Type: CNAME
Name: go
Target: claritysystems.work
Proxy: Proxied / orange cloud
TTL: Auto

Cloudflare Worker route added:

go.claritysystems.work/*

attached to:

affilliates-worker

Important: kept existing route too:

affiliates.claritysystems.work/*

Result:

Both routes can work, but admin-generated public links now use the cleaner go subdomain.


7. Changed admin panel generated affiliate links

Problem:

Admin panel hardcoded generated links as:

const link = "https://affiliates.claritysystems.work/r/" + a.id;

Fix:

Changed to:

const link = "https://go.claritysystems.work/r/" + a.id;

File changed:

workers/affiliates-worker/src/index.js

Terminal command used:

perl -pi -e 's#https://affiliates\.claritysystems\.work/r/#https://go.claritysystems.work/r/#g' workers/affiliates-worker/src/index.js

Verification:

grep -n "claritysystems.work/r/" workers/affiliates-worker/src/index.js

Expected:

const link = "https://go.claritysystems.work/r/" + a.id;

Result:

The admin panel now generates:

https://go.claritysystems.work/r/ckl244

8. Diagnosed DNS issue on Mac

Problem:

The new go link worked when DNS was forced, but the browser showed:

DNS_PROBE_FINISHED_NXDOMAIN

and terminal showed:

curl: (6) Could not resolve host: go.claritysystems.work

Diagnosis:

Cloudflare DNS was working:

dig @1.1.1.1 go.claritysystems.work

returned Cloudflare IPs.

But local Mac/router DNS was stale:

nslookup go.claritysystems.work

used:

Server: 192.168.100.1

and returned no answer.

Fix:

Changed Mac Wi-Fi DNS via terminal:

sudo networksetup -setdnsservers "Wi-Fi" 1.1.1.1 1.0.0.1 8.8.8.8

Verified:

networksetup -getdnsservers "Wi-Fi"

Expected:

1.1.1.1
1.0.0.1
8.8.8.8

Then flushed DNS:

sudo dscacheutil -flushcache
sudo killall -HUP mDNSResponder

Result:

go.claritysystems.work resolved in browser and redirected correctly.


9. Final working flow

Current final flow:

Lovinia logs into admin:
https://affiliates.claritysystems.work/admin

Admin generates public affiliate link:
https://go.claritysystems.work/r/ckl244

Visitor clicks link.

Worker logs click and redirects to:
https://claritysystems.work/sales-training/?ref=ckl244

Visitor clicks around internal pages.

Ref persists as:
?ref=ckl244

Visitor submits enquiry / registration.

Form and Worker can read ref for D1 tracking and affiliate attribution.

10. Final commits made

Relevant commits:

fix affiliates worker relative redirects
rename worker to affilliates-worker
persist affiliate ref across internal site links
add affiliate ref persistence to standalone sales pages
add affiliate ref persistence across all standalone pages
add affiliate ref persistence to home page
use go subdomain for public affiliate links

Final status

Working:

Affiliate admin login
Affiliate creation
Generated affiliate links
go.claritysystems.work redirect route
D1 affiliate lookup
Click redirect
Ref persistence across main internal pages
Mac DNS resolution after changing DNS servers

Still future work:

Affiliate dashboard reporting
Commission calculation
Telegram affiliate notifications
Email blast
Portal signup
Full affiliate conversion dashboard